package com.xiaofeng.server.service.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.xiaofeng.api.enums.CompleteStatusEnum;
import com.xiaofeng.api.enums.IsDeletedFlagEnum;
import com.xiaofeng.api.enums.SubjectInfoTypeEnum;
import com.xiaofeng.api.req.GetPracticeSubjectsReq;
import com.xiaofeng.api.vo.*;
import com.xiaofeng.server.dao.*;
import com.xiaofeng.server.entity.dto.CategoryDTO;
import com.xiaofeng.server.entity.dto.PracticeSubjectDTO;
import com.xiaofeng.server.entity.po.*;
import com.xiaofeng.server.service.PracticeSetService;
import com.xiaofeng.server.util.LoginUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.List;

/**
 * 套题信息表(PracticeSet)表服务实现类
 *
 * @author makejava
 * @since 2024-04-17 14:05:57
 */
@Service("practiceSetService")
@Slf4j
public class PracticeSetServiceImpl implements PracticeSetService {

    @Resource
    private SubjectMappingDao subjectMappingDao;

    @Resource
    private SubjectCategoryDao subjectCategoryDao;

    @Resource
    private SubjectLabelDao subjectLabelDao;

    @Resource
    private PracticeSetDao practiceSetDao;

    @Resource
    private PracticeSetDetailDao practiceSetDetailDao;

    @Resource
    private SubjectDao subjectDao;

    @Resource
    private PracticeDetailDao practiceDetailDao;

    @Resource
    private PracticeDao practiceDao;

    @Override
    public List<SpecialPracticeVO> getSpecialPracticeContent() {
        //练题信息
        List<SpecialPracticeVO> specialPracticeVOList = new LinkedList<>();
        LinkedList<Integer> subjectTypeList = new LinkedList<>();
        //练题模块的题目类型（例如单选、多选、判断）
        subjectTypeList.add(SubjectInfoTypeEnum.RADIO.getCode());
        subjectTypeList.add(SubjectInfoTypeEnum.MULTIPLE.getCode());
        subjectTypeList.add(SubjectInfoTypeEnum.JUDGE.getCode());
        //分类DTO
        CategoryDTO categoryDTO = new CategoryDTO();
        categoryDTO.setSubjectTypeList(subjectTypeList);
        //通过传入题目类型查询分类大类
        List<PrimaryCategoryPO> poList = subjectCategoryDao.getPrimaryCategory(categoryDTO);
        //判断是否为空，空的话返回空数据
        if (CollectionUtils.isEmpty(poList)) {
            return specialPracticeVOList;
        }
        //循环遍历
        poList.forEach(primaryCategoryPO -> {
            //封装练题信息specialPracticeVO
            SpecialPracticeVO specialPracticeVO = new SpecialPracticeVO();
            //设置分类Id
            specialPracticeVO.setPrimaryCategoryId(primaryCategoryPO.getParentId());
            //传入父级Id查询分类的大类（父级）
            CategoryPO categoryPO = subjectCategoryDao.selectById(primaryCategoryPO.getParentId());
            //设置分类大类名
            specialPracticeVO.setPrimaryCategoryName(categoryPO.getCategoryName());
            CategoryDTO categoryDTOTemp = new CategoryDTO();
            //设置分类类型
            categoryDTOTemp.setCategoryType(2);
            //设置父级Id
            categoryDTOTemp.setParentId(primaryCategoryPO.getParentId());
            //查询分类
            List<CategoryPO> smallPoList = subjectCategoryDao.selectList(categoryDTOTemp);
            //判断是否为空
            if (CollectionUtils.isEmpty(smallPoList)) {
                return;
            }
            //封装练习的分类
            List<SpecialPracticeCategoryVO> categoryList = new LinkedList<>();
            //循环
            smallPoList.forEach(smallPo ->{
                //传入分类类型、分类id查询分类属于的标签
               List<SpecialPracticeLabelVO> labelVOList =  getLabelVOList(smallPo.getId(),subjectTypeList);
               if (CollectionUtils.isEmpty(labelVOList)){
                   return;
               }
               //封装练题分类
                SpecialPracticeCategoryVO specialPracticeCategoryVO = new SpecialPracticeCategoryVO();
               //设置分类Id
                specialPracticeCategoryVO.setCategoryId(smallPo.getId());
                //设置分类名称
                specialPracticeCategoryVO.setCategoryName(smallPo.getCategoryName());
                //封装标签
                List<SpecialPracticeLabelVO> labelList = new LinkedList<>();
                //循环遍历出标签信息
                labelVOList.forEach(labelVO ->{
                    SpecialPracticeLabelVO specialPracticeLabelVO = new SpecialPracticeLabelVO();
                    //设置标签Id
                    specialPracticeLabelVO.setId(labelVO.getId());
                    //设置分类Id
                    specialPracticeLabelVO.setAssembleId(labelVO.getAssembleId());
                    //设置标签名称
                    specialPracticeLabelVO.setLabelName(labelVO.getLabelName());
                    //添加到labelList
                    labelList.add(specialPracticeLabelVO);
                });
                //将标签类的信息设置到练题分类属性里面
               specialPracticeCategoryVO.setLabelList(labelList);
               //分类列表完成，返回
               categoryList.add(specialPracticeCategoryVO);
            });
            //练题总体信息封装完成
            specialPracticeVO.setCategoryList(categoryList);
            specialPracticeVOList.add(specialPracticeVO);
        });
        //返回整体的练题信息(包括练题分类信息、练题标签信息)
        return specialPracticeVOList;
    }

    /**
     * 添加套题信息
     * @param dto
     * @return
     */
    @Transactional
    @Override
    public PracticeSetVo addPractice(PracticeSubjectDTO dto) {
        //套卷信息设置
        PracticeSetVo setVo = new PracticeSetVo();
        //获取练题详细信息
        List<PracticeSubjectDetailVO> practiceList = getPracticeList(dto);
        //判断是否为空
        if (CollectionUtils.isEmpty(practiceList)) {
            return setVo;
        }
        // 套卷信息类
        PracticeSetPO practiceSetPO = new PracticeSetPO();
        //设置套卷类型
        practiceSetPO.setSetType(1);
        //分类和标签集合
        List<String> assembleIds = dto.getAssembleIds();
        //set列表（无序，不可重复）
        Set<Long> categoryIdSet = new HashSet<>();
        //循环将分类标签集合体中的分类id取出来保存到set中
        assembleIds.forEach(assembleId ->{
            Long categoryId = Long.valueOf(assembleId.split("-")[0]);
            categoryIdSet.add(categoryId);
        });
        StringBuffer setName = new StringBuffer();
        int i = 1;
        for (Long categoryId : categoryIdSet) {
            if (i > 2){
                break;
            }
            //根据分类Id查询标签信息
            CategoryPO categoryPO = subjectCategoryDao.selectById(categoryId);
            //将分类Id添加到StringBuffer
            setName.append(categoryPO.getCategoryName());
            setName.append("、");
            i = i + 1;
        }
        //把最后的逗号删除
        setName.deleteCharAt(setName.length() - 1);
        if (i == 2){
            setName.append("专项练习");
        }else {
            setName.append("等专项的练习");
        }
        //设置套题的套题名称
        practiceSetPO.setSetName(setName.toString());
        //取出标签id
        String labelId = assembleIds.get(0).split("-")[1];
        //通过标签Id查询标签信息
        SubjectLabelPO labelPO = subjectLabelDao.queryById(Long.valueOf(labelId));
        //标签的大类Id（代表该标签属于哪个分类）
        practiceSetPO.setPrimaryCategoryId(labelPO.getCategoryId());
        practiceSetPO.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        practiceSetPO.setCreatedBy(LoginUtil.getLoginId());
        practiceSetPO.setCreatedTime(new Date());
        //保存套卷信息（套题id，题目id，题目类型id）
        practiceSetDao.add(practiceSetPO);
        //获取套题的Id
        Long practiceSetId = practiceSetPO.getId();
        //思考，这里为什么不符合规范
        //设置套内容表信息
        practiceList.forEach(e ->{
            PracticeSetDetailPO detailPO = new PracticeSetDetailPO();
            detailPO.setSetId(practiceSetId);
            detailPO.setSubjectId(e.getSubjectId());
            detailPO.setSubjectType(e.getSubjectType());
            detailPO.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
            detailPO.setCreatedBy(LoginUtil.getLoginId());
            detailPO.setCreatedTime(new Date());
            practiceSetDetailDao.add(detailPO);
        });
        setVo.setSetId(practiceSetId);
        return setVo;
    }

    @Override
    public PracticeSubjectListVO getSubjects(GetPracticeSubjectsReq req) {
        // 获取练习id
        Long setId = req.getSetId();
        PracticeSubjectListVO vo = new PracticeSubjectListVO();
        List<PracticeSubjectDetailVO> practiceSubjectListVOS  = new LinkedList<>();
        List<PracticeSetDetailPO> practiceSetDetailPOS  =practiceSetDetailDao.selectBySetId(setId);
        if (CollectionUtils.isEmpty(practiceSetDetailPOS)){
            return vo;
        }
        String loginId = LoginUtil.getLoginId();
        Long practiceId = req.getPracticeId();
        practiceSetDetailPOS.forEach(e ->{
            PracticeSubjectDetailVO practiceSubjectListVO = new PracticeSubjectDetailVO();
            practiceSubjectListVO.setSubjectId(e.getSubjectId());
            practiceSubjectListVO.setSubjectType(e.getSubjectType());
            if (Objects.nonNull(practiceId)){
                PracticeDetailPO practiceDetailPO = practiceDetailDao.selectDetail(practiceId, e.getSubjectId(), loginId);
                if (Objects.nonNull(practiceDetailPO) && StringUtils.isNotBlank(practiceDetailPO.getAnswerContent())){
                    practiceSubjectListVO.setIsAnswer(1);
                }else{
                    practiceSubjectListVO.setIsAnswer(0);
                }

            }
            practiceSubjectListVOS.add(practiceSubjectListVO);
        });
        vo.setSubjectList(practiceSubjectListVOS);
        PracticeSetPO practiceSetPO = practiceSetDao.selectById(setId);
        vo.setTitle(practiceSetPO.getSetName());
        if (Objects.isNull(practiceId)){
            Long newPracticeId = insertUnCompletePractice(setId);
            vo.setPracticeId(newPracticeId);
        }else{
            updateUnCompletePractice(practiceId);
            PracticePO practicePO = practiceDao.selectById(practiceId);
            vo.setTimeUse(practicePO.getTimeUse());
            vo.setPracticeId(practiceId);
        }
        return vo;
    }

    private void updateUnCompletePractice(Long practiceId) {
        PracticePO practicePO = new PracticePO();
        practicePO.setId(practiceId);
        practicePO.setSubmitTime(new Date());
        practiceDao.update(practicePO);
    }

    private Long insertUnCompletePractice(Long practiceSetId) {
        PracticePO practicePO = new PracticePO();
        practicePO.setSetId(practiceSetId);
        practicePO.setCompleteStatus(CompleteStatusEnum.NO_COMPLETE.getCode());
        practicePO.setTimeUse("00:00:00");
        practicePO.setSubmitTime(new Date());
        practicePO.setCorrectRate(new BigDecimal("0.00"));
        practicePO.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        practicePO.setCreatedBy(LoginUtil.getLoginId());
        practicePO.setCreatedTime(new Date());
        practiceDao.insert(practicePO);
        return practicePO.getId();
    }

    /**
     * 开始练习方法的抽取
     * 获取对应类型的练题列表
     * @param dto
     * @return
     */
    private List<PracticeSubjectDetailVO> getPracticeList(PracticeSubjectDTO dto) {
        //套卷练题详细信息VOS
        List<PracticeSubjectDetailVO> practiceSubjectListVOS = new LinkedList<>();
        //避免重复
        List<Long> excludeSubjectIds = new LinkedList<>();
        //设置题目数量，之后优化到nacos动态配置
        Integer radioSubjectCount = 10;
        Integer multipleSubjectCount = 6;
        Integer judgeSubjectCount = 4;
        Integer totalSubjectCount = 20;
        //--------------------工厂+适配器模型--------//
        //查询单选
        dto.setSubjectCount(radioSubjectCount);
        dto.setSubjectType(SubjectInfoTypeEnum.RADIO.getCode());
        assembleList(dto,practiceSubjectListVOS,excludeSubjectIds);
        //查询多选
        dto.setSubjectCount(multipleSubjectCount);
        dto.setSubjectType(SubjectInfoTypeEnum.MULTIPLE.getCode());
        assembleList(dto,practiceSubjectListVOS,excludeSubjectIds);
        //查询判断
        dto.setSubjectCount(judgeSubjectCount);
        dto.setSubjectType(SubjectInfoTypeEnum.JUDGE.getCode());
        assembleList(dto,practiceSubjectListVOS,excludeSubjectIds);
        //----------------工厂+适配器模型-------//
        //补充的题目
        if (practiceSubjectListVOS.size() == totalSubjectCount) {
            return practiceSubjectListVOS;
        }
        //查看剩余可设置的题目数量（设置的题目总数减去已经设置的题目）
        Integer remainCount = totalSubjectCount - practiceSubjectListVOS.size();
        //设置补充题目的数量
        dto.setSubjectCount(remainCount);
        //默认设置为单选题
        dto.setSubjectType(1);
        assembleList(dto,practiceSubjectListVOS,excludeSubjectIds);
        //返回list列表
        return practiceSubjectListVOS;
    }

    private List<PracticeSubjectDetailVO> assembleList(PracticeSubjectDTO dto, List<PracticeSubjectDetailVO> list, List<Long> excludeSubjectIds) {
        //要排除的题目id
        dto.setExcludeSubjectIds(excludeSubjectIds);
        // 获取练习面试题目信息
        List<SubjectPO> subjectPOList = subjectDao.getPracticeSubject(dto);
        //判断是否为空
        if (CollectionUtils.isEmpty(subjectPOList)) {
            return list;
        }
        //循环遍历
        subjectPOList.forEach(e ->{
            //套卷题目详情信息
            PracticeSubjectDetailVO vo = new PracticeSubjectDetailVO();
            //设置题目Id
            vo.setSubjectId(e.getId());
            //设置题目类型
            vo.setSubjectType(e.getSubjectType());
            //排除的题目id
            excludeSubjectIds.add(e.getId());
            //添加到list集合中去
            list.add(vo);
        });
        return list;
    }


    private List<SpecialPracticeLabelVO> getLabelVOList(Long categoryId, LinkedList<Integer> subjectTypeList) {
        //查出标签列表
        List<LabelCountPO> countPOList = subjectMappingDao.getLabelSubjectCount(categoryId,subjectTypeList);
        //判断是否为空
        if (CollectionUtils.isEmpty(countPOList)){
            return Collections.emptyList();
        }
        LinkedList<SpecialPracticeLabelVO> voList = new LinkedList<>();
        //循环
        countPOList.forEach(countPO ->{
            //封装练题标签信息
            SpecialPracticeLabelVO vo = new SpecialPracticeLabelVO();
            //设置标签Id
            vo.setId(countPO.getLabelId());
            //设置分类Id
            vo.setAssembleId(categoryId + "-" + countPO.getLabelId());
            //通过上面的标签Id查询标签具体信息
            SubjectLabelPO subjectLabelPO = subjectLabelDao.queryById(countPO.getLabelId());
            //设置标签名
            vo.setLabelName(subjectLabelPO.getLabelName());
            //添加进List集合里面
            voList.add(vo);
        });
        //返回
        return voList;
    }
}
